//-----------------------------------------------------------------------
// <copyright file="Log4NetLogger.cs" company="Company" author="Nagarro">
//  All rights reserved. Copyright (c) 2013.
// </copyright>
// <summary>This is the Log4NetLogger class.</summary>
//-----------------------------------------------------------------------

namespace Company.Project.Shared
{
    using System;
    using log4net;

    /// <summary>
    /// Represents logger implementation for Log 4 Net.
    /// </summary>
    public sealed class Log4NetLogger : ILogger
    {
        /// <summary>
        /// Logging instance variable.
        /// </summary>
        private static readonly log4net.ILog LoggerObject = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// The variable is declared to be volatile to ensure that assignment to the 
        /// log4NetInstance variable completes before the instance variable can be accessed.
        /// </summary>
        private static volatile Log4NetLogger log4NetInstance;

        /// <summary>
        /// Synchronization object.
        /// </summary>
        private static object syncObject = new object();
        
        /// <summary>
        /// Is Debug Enabled.
        /// </summary>
        private readonly bool isDebugEnabled;

        /// <summary>
        /// Is Error Enabled.
        /// </summary>
        private readonly bool isErrorEnabled;

        /// <summary>
        /// Is Information Enabled.
        /// </summary>
        private readonly bool isInfoEnabled;

        /// <summary>
        /// Is Warning Enabled.
        /// </summary>
        private readonly bool isWarningEnabled;        

        /// <summary>
        /// Initializes a new instance of the <see cref="Log4NetLogger"/> class.
        /// </summary>
        public Log4NetLogger()
        {
            log4net.Config.XmlConfigurator.Configure();
            this.isDebugEnabled = LoggerObject.IsDebugEnabled;
            this.isInfoEnabled = LoggerObject.IsInfoEnabled;
            this.isWarningEnabled = LoggerObject.IsWarnEnabled;
            this.isErrorEnabled = LoggerObject.IsErrorEnabled;
        }

        /// <summary>
        /// Gets the instance is private static property to return the same Instance of the class every time.
        /// Note: Double - checked serialized initialization of class pattern is used.
        /// </summary>
        /// <value>Logging instance.</value>
        public static Log4NetLogger Instance
        {
            get
            {
                // Check for null before acquiring the lock.
                if (log4NetInstance == null)
                {
                    // Use a syncObject to lock on, to avoid deadlocks among multiple threads.
                    lock (syncObject)
                    {
                        // Again check if log4NetInstance has been initialized, 
                        // since some other thread may have acquired the lock first and constructed the object.
                        if (log4NetInstance == null)
                        {
                            log4NetInstance = new Log4NetLogger();
                        }
                    }
                }

                return log4NetInstance;
            }
        }

        /// <summary>
        /// The debug information.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Debug(object message)
        {
            if (this.isDebugEnabled)
            {
                LoggerObject.Debug(message);
            }
        }

        /// <summary>
        /// The error message.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Error(string message)
        {
            if (this.isErrorEnabled)
            {
                LoggerObject.Error(message);
            }
        }

        /// <summary>
        /// The error message.
        /// </summary>
        /// <param name="exceptionToLog">The message.</param>
        public void Error(Exception exceptionToLog)
        {
            if (this.isErrorEnabled)
            {
                LoggerObject.Error(exceptionToLog);
            }
        }

        /// <summary>
        /// The error message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="exception">The exception.</param>
        public void Error(object message, Exception exception)
        {
            if (this.isErrorEnabled)
            {
                LoggerObject.Error(message, exception);
            }
        }

        /// <summary>
        /// The information method.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Info(object message)
        {
            if (this.isInfoEnabled)
            {
                LoggerObject.Info(message);
            }
        }

        /// <summary>
        /// The Warning method.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Warning(object message)
        {
            if (this.isWarningEnabled)
            {
                LoggerObject.Warn(message);
            }
        }
    }
}